package cn.itcast.hotel;

import cn.itcast.hotel.mapper.HotelMapper;
import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.service.impl.HotelServiceImpl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;

@SpringBootTest
public class MyHotelDoc {
    private RestHighLevelClient client;
    @Autowired
    private HotelMapper hotelMapper;

    /**
     * 创建连接
     */
    @BeforeEach
    void setUpDoc() throws IOException {
        this.client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://113.45.170.115:9200")));
    }

    /**
     * 关闭连接
     */
    @AfterEach
    void setDownDoc() throws IOException {
        this.client.close();
    }

    //    创建文档
    @Test
    void creatDoc() throws IOException {
/*//        1.创建请求对象
        IndexRequest hotel = new IndexRequest("hotel").id("1");
//        2.准备JSON文档数据
        HotelDoc hotelDoc = new HotelDoc();
        hotelDoc.setId(1L);
        hotelDoc.setName("tom");
        hotelDoc.setCity("cd");
        hotelDoc.setAddress("成都");
//        2.1 把doc转换成json
        String jsonString = JSON.toJSONString(hotelDoc);
        hotel.source(jsonString, XContentType.JSON);
//        3.发送请求
        client.index(hotel, RequestOptions.DEFAULT);*/
/**
 * 从数据库中查询，之后添加到es中
 */
//      1.查询数据库数据
        Hotel hotel = hotelMapper.selectById(60214);
//        2.将DB转成ES的doc
        HotelDoc hotelDoc = new HotelDoc(hotel);
//        3.对象--->json
        String jsonString = JSON.toJSONString(hotelDoc);
//        4.创建请求
        IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());
//        5.封装数据
        request.source(jsonString, XContentType.JSON);
//        6.发送请求
        client.index(request, RequestOptions.DEFAULT);
    }

    //    查询文档
    @Test
    void getDoc() throws IOException {
//        1.创建请求
        GetRequest hotel = new GetRequest("hotel", "60214");
//        2.发送请求获取结果
        GetResponse documentFields = client.get(hotel, RequestOptions.DEFAULT);
//        3.解析结果
        String json = documentFields.getSourceAsString();
//        4.将获取到的json转成doc对象
        HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
        System.out.println(hotelDoc);
    }

    //    删除文档
    @Test
    void delDoc() throws IOException {
//
//        1.创建删除请求
        DeleteRequest request = new DeleteRequest("hotel", "60214");
//        2.发送请求
        client.delete(request, RequestOptions.DEFAULT);
    }

    //    修改文档
    @Test
    void updateDoc() throws IOException {
//        1.创建更新请求
        UpdateRequest hotel = new UpdateRequest("hotel", "1");
//        2.准备修改参数key value
        hotel.doc(
                "city", "北京",
                "name", "jack"
        );
//        3.更新文档
        client.update(hotel, RequestOptions.DEFAULT);
    }

    /**
     * 批量导入文档数据====for循环
     */
//    TODO 后续需要改造成多线程的操作
    @Test
    void bulkCreatDoc() throws IOException {
//        先将DB数据查询出来放到list集合中
        List<Hotel> hotels = hotelMapper.selectList(null);
//        1.创建bulk对象
        BulkRequest bulkRequest = new BulkRequest();
//        2.将多个db转换成doc
        for (Hotel hotel : hotels) {
            HotelDoc hotelDoc = new HotelDoc(hotel);
            bulkRequest.add(new IndexRequest("hotel")
                    .id(hotelDoc.getId().toString())
//                    组成DSL语句，封装数据
                    .source(JSON.toJSONString(hotelDoc), XContentType.JSON));
        }
//         3.发送请求，bulk批处理
        client.bulk(bulkRequest, RequestOptions.DEFAULT);
    }

    /**
     * 使用每一页作为一个批次进行导入
     * 按照10条数据作为一页 进行一个批次的导入
     */
    @Autowired
    private HotelServiceImpl hotelService;

    @Test
    void pageBulkCreatDoc() throws IOException {
        Integer allCount = hotelMapper.selectCount(null);
//        十条数据为一页
        Integer pageSize = 10;
//        一共有多少页的处理
        Integer allPage = allCount % pageSize == 0 ? allCount / pageSize : allCount / pageSize + 1;
//        循环处理这每一页的数据
        for (Integer i = 1; i <= allPage; i++) {
//          使用mp的分页获取数据
            IPage<Hotel> pageInfo = new Page<>(i, pageSize);
//          执行分页查询 不需要执行 直接在pageInfo中有数据
//            TODO 为什么不能使用mapper中的，因为MP本身就有基本的sql功能
            IPage<Hotel> page = hotelService.page(pageInfo);
            List<Hotel> hotels = page.getRecords();
//           处理每一批次的数据(每次处理的请求不一样 所以需要每次的请求创建不一样)
            BulkRequest bulkRequest = new BulkRequest();
            for (Hotel hotel : hotels) {
                HotelDoc hotelDoc = new HotelDoc(hotel);
                bulkRequest.add(new IndexRequest("hotel")
                        .id(hotelDoc.getId().toString())
                        .source(JSON.toJSONString(hotelDoc), XContentType.JSON));
            }
//          一次发送数据请求，bulk
            client.bulk(bulkRequest, RequestOptions.DEFAULT);
        }
    }

    //    TODO 使用多线程


    @Autowired
    private ThreadPoolExecutor myTreadPool;

    @Test
    void poolCreatDoc() throws IOException {
        Integer allCount = hotelMapper.selectCount(null);
//        十条数据为一页
        Integer pageSize = 10;
//        一共有多少页的处理
        Integer allPage = allCount % pageSize == 0 ? allCount / pageSize : allCount / pageSize + 1;
//        循环处理这每一页的数据
        for (Integer i = 1; i <= allPage; i++) {
//          使用mp的分页获取数据,使用线程池
//            使用构造器传参数给i和pageSize
            RunableTask runableTask = new RunableTask(i, pageSize);
//            等价于每次循环一次就从线程池中拿一个线程去执行
            myTreadPool.submit(runableTask);
        }
    }

    class RunableTask implements Runnable {
        //        经典的构造器传参数
        int i;
        int pageSize;

        public RunableTask(Integer i, Integer pageSize) {
            this.i = i;
            this.pageSize = pageSize;
        }

        @Override
        public void run() {
            IPage<Hotel> pageInfo = new Page<>(i, pageSize);
//          执行分页查询 不需要执行 直接在pageInfo中有数据
//            TODO 为什么不能使用mapper中的，因为MP本身就有基本的sql功能
            IPage<Hotel> page = hotelService.page(pageInfo);
            List<Hotel> hotels = page.getRecords();
//           处理每一批次的数据(每次处理的请求不一样 所以需要每次的请求创建不一样)
            BulkRequest bulkRequest = new BulkRequest();
            for (Hotel hotel : hotels) {
                HotelDoc hotelDoc = new HotelDoc(hotel);
                bulkRequest.add(new IndexRequest("hotel")
                        .id(hotelDoc.getId().toString())
                        .source(JSON.toJSONString(hotelDoc), XContentType.JSON));
            }
//          一次发送数据请求，bulk
            try {
                client.bulk(bulkRequest, RequestOptions.DEFAULT);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

